//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Eas.WebCrawler.Interfaces;

namespace Eas.WebCrawler.Test.Interfaces {
    /// <summary>
    /// Summary description for RequestTest
    /// </summary>
    [TestClass]
    public class RequestTest {
        public RequestTest() {
            //
            // TODO: Add constructor logic here
            //
        }

        private static readonly Uri Yahoo = new Uri("http://www.yahoo.com");
        private static readonly Uri Google = new Uri("http://www.google.com");
        private static readonly Uri Partial = new Uri("default.aspx", UriKind.RelativeOrAbsolute);
        private static readonly Request BaseReqeust = new Request("http://www.google.com", null);

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void MyTestInitialize() {
            //System.Diagnostics.Debugger.Break(); 
        }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        /// <summary>Executes the ConstrructSimpleRequest test.</summary>
        public void ConstrructSimpleRequest() {
            Eas.WebCrawler.Interfaces.Request r;
            r = new Request("http://www.google.com");
            Assert.AreEqual<Uri>(r.Uri, Google);
            Assert.IsNull(r.Parent);
            Assert.AreEqual<int>(r.Depth, 0);
            r = new Request(new Uri("http://www.google.com"));
            Assert.AreEqual<Uri>(r.Uri, Google);
            Assert.IsNull(r.Parent);
            Assert.AreEqual<int>(r.Depth, 0);
        }

        [TestMethod]
        /// <summary>Executes the TestParentRequest test.</summary>
        public void TestParentRequest() {
            Eas.WebCrawler.Interfaces.Request r;
            r = new Request("http://www.google.com");
            Eas.WebCrawler.Interfaces.Request child = new Request("http://www.yhahoo.com", r);
            Assert.AreEqual<int>(child.Depth, 1);
            Assert.AreEqual<Uri>(child.Parent.Uri, Google);
        }

        [TestMethod]
        /// <summary>Executes the TestUrlFailedEventArg test.</summary>
        public void TestUrlFailedEventArg() {
            TestProcessingState state = new TestProcessingState( 15,  RequestHelper.rGoogle, true, null);
            UrlFailedEventArgs args = new UrlFailedEventArgs( state, "erik", 404);
            Assert.AreEqual<int>(15, args.State.Id);
            Assert.AreEqual<string>("erik", args.ResultDescription);
            Assert.AreEqual<int>(404, args.ResultCode);
            Assert.AreEqual<Uri>(UriHelper.Google, args.State.Request.Uri);
            Assert.AreEqual<int>(args.GetHashCode(), UriHelper.Google.GetHashCode());
            Assert.IsFalse(args.Equals("eee"));
            Assert.AreEqual<UrlFailedEventArgs>(args, new UrlFailedEventArgs(state, "rrr", 500));
        }

        [TestMethod]
        /// <summary>Executes the TestUrlCompletedArgs test.</summary>
        public void TestUrlCompletedArgs() {
            UrlCompletedEventArgs args = CreateArgs(14, true, null, RequestHelper.rGoogle, null);
            Assert.AreEqual<bool>(true, args.State.IsTextResponse);
            Assert.AreEqual<int>(14, args.State.Id);
            Assert.IsNull(args.Storage);
            Assert.AreEqual<Request>(RequestHelper.rGoogle, args.State.Request);
            Assert.AreEqual<int>(RequestHelper.rGoogle.GetHashCode(), args.GetHashCode());
            Assert.IsFalse(args.Equals("eee"));
            Assert.AreEqual<UrlCompletedEventArgs>(args, CreateArgs(23, false, null, RequestHelper.rGoogle, null));
        }

        [TestMethod]
        /// <summary>Executes the TestMessageEventArgs test.</summary>
        public void TestMessageEventArgs() {
            TestProcessingState state = new TestProcessingState(3);
            state._Request = RequestHelper.rGoogle;
            ProcessingStateMessageEventArgs args = new ProcessingStateMessageEventArgs(state, "erik");
            Assert.AreEqual<int>(3, args.State.Id);
            Assert.AreEqual<Request>(RequestHelper.rGoogle, args.State.Request);
            Assert.AreEqual<int>(RequestHelper.rGoogle.Uri.GetHashCode(), args.State.Request.Uri.GetHashCode());
            Assert.AreEqual<string>("erik", args.Message);
            Assert.AreEqual<int>(("erik").GetHashCode(), args.GetHashCode());
            Assert.AreEqual<ProcessingStateMessageEventArgs>(new ProcessingStateMessageEventArgs(new TestProcessingState(4), "erik"), args);
            Assert.AreNotEqual<ProcessingStateMessageEventArgs>(new ProcessingStateMessageEventArgs(new TestProcessingState(3), "serik"), args);
            Assert.AreNotEqual(args, "erik");
        }

        [TestMethod]
        /// <summary>Executes the TestProcessingStateEventArgs test.</summary>
        public void TestProcessingStateEventArgs() {
            TestProcessingState state1a = new TestProcessingState(1);
            TestProcessingState state1b = new TestProcessingState(1);
            TestProcessingState state2 = new TestProcessingState(2);

            ProcessingStateEventArgs args1a = new ProcessingStateEventArgs(state1a);
            ProcessingStateEventArgs args1b = new ProcessingStateEventArgs(state1b);
            ProcessingStateEventArgs args2 = new ProcessingStateEventArgs(state2);
            
            object o = new object();

            Assert.AreEqual<int>(1, args1a.GetHashCode());
            Assert.AreEqual<int>(1, args1b.GetHashCode());
            Assert.AreEqual<int>(2, args2.GetHashCode());

            Assert.AreEqual<ProcessingStateEventArgs>(args1a, args1b);
            Assert.AreEqual<ProcessingStateEventArgs>(args1b, args1a);
            Assert.AreEqual<ProcessingStateEventArgs>(args1a, args1a);
            Assert.AreNotEqual<ProcessingStateEventArgs>(args1a, args2);
            Assert.AreNotEqual<ProcessingStateEventArgs>(args1b, args2);
            Assert.AreNotEqual<ProcessingStateEventArgs>(args1a, args2);
            Assert.AreNotEqual<ProcessingStateEventArgs>(args1b, args2);
            Assert.AreNotEqual(args1a, o);
            Assert.AreNotEqual(o, args2);



        }


        [TestMethod]
        [ExpectedException(typeof(System.ArgumentNullException))]
        /// <summary>Executes the TestNullUriRequest test, in which the <seealso cref="System.ArgumentNullException"/> exception should be thrown during a succesfull test run.</summary>
        public void TestNullUriRequest() {

            Uri uri = null;
            new Request(uri);
            return;

        }

        [TestMethod]
        [ExpectedException(typeof(System.ArgumentNullException))]
        /// <summary>Executes the TestNullStringRequest test, in which the <seealso cref="System.ArgumentNullException"/> exception should be thrown during a succesfull test run.</summary>
        public void TestNullStringRequest() {
            
                string s = null;
                new Request(s);
                return;

        }

        [TestMethod]
        [ExpectedException(typeof(System.ArgumentOutOfRangeException))]
        /// <summary>Executes the EmptyStringRequestTest test, in which the <seealso cref="System.ArgumentOutOfRangeException"/> exception should be thrown during a succesfull test run.</summary>
        public void EmptyStringRequestTest() {
                new Request("");
        }

        [TestMethod]
        /// <summary>Executes the PartialTestRequestConstruction test.</summary>
        public void PartialTestRequestConstruction() {
            Request r = new Request("default.aspx", new Request(Google));
            CheckRequest(r, Partial, 0, new Request(Google));
        }

        [TestMethod]
        /// <summary>Executes the TestHascode test.</summary>
        public void TestHascode() {
            Assert.AreEqual<int>(BaseReqeust.GetHashCode(), Google.GetHashCode());
        }

        [TestMethod]
        /// <summary>Executes the TestRequestEquality test.</summary>
        public void TestRequestEquality() {
            Request r = new Request(Google, BaseReqeust);
            Assert.AreEqual<Request>(r, BaseReqeust);
            Assert.AreEqual(r, BaseReqeust);
            Request p = new Request(Yahoo, null);
            Assert.AreNotEqual<Request>(p, BaseReqeust);
            Assert.AreNotEqual(p, BaseReqeust);
            Assert.AreEqual<int>(Google.GetHashCode(), r.GetHashCode());
        }

        [TestMethod]
        /// <summary>Executes the CheckNullComparisonTest test.</summary>
        public void CheckNullComparisonTest() {
            Assert.IsFalse(BaseReqeust.Equals(BaseReqeust.Parent));
            Assert.IsFalse(BaseReqeust.Equals("hello"));
        }

        [TestMethod]
        /// <summary>Executes the TestPartialUri test.</summary>
        public void TestPartialUri() {
            Uri targetUri = new Uri("http://www.google.com/default.aspx");
            
            Request req = new Request(Partial, new Request(Google));
            Assert.AreEqual<Uri>(targetUri, req.Uri);

            req = new Request(Partial.ToString(), new Request(Google));
            Assert.AreEqual<Uri>(targetUri, req.Uri);

            req = new Request(Google.ToString(), null);
            Assert.AreEqual<Uri>(Google, req.Uri);

            req = new Request(Google, null);
            Assert.AreEqual<Uri>(Google, req.Uri);

            Request rgoogle = new Request(Google);
            Request rpartial = new Request(Partial, rgoogle);

            Assert.AreNotEqual<Request>(rgoogle, rpartial);

        }

        [TestMethod]
        [ExpectedException(typeof(System.ArgumentOutOfRangeException))]
        /// <summary>Executes the TestUnrootedRelativeUri test, in which the <seealso cref="System.ArgumentOutOfRangeException"/> exception should be thrown during a succesfull test run.</summary>
        public void TestUnrootedRelativeUri() {
            Request r = new Request(Partial);
        }

        [TestMethod]
        /// <summary>Executes the TestToString test.</summary>
        public void TestToString() {
            Request rGoogle = new Request(Google, null);
            Request rYahoo = new Request(Yahoo, null);
            Request rPartial = new Request(Partial, rGoogle);

            Assert.AreEqual<string>(Google.ToString(), rGoogle.ToString());
            Assert.AreEqual<string>("http://www.yahoo.com/", rYahoo.ToString());
            Assert.AreEqual<string>("http://www.google.com/default.aspx", rPartial.Uri.ToString());
        }

        [TestMethod]
        /// <summary>Executes the TestDepth test.</summary>
        public void TestDepth() {
            Assert.AreEqual<int>(0, RequestHelper.rGoogle.Depth);
            Assert.AreEqual<int>(1, RequestHelper.rPartial.Depth);
            Assert.AreEqual<int>(2, RequestHelper.r2Deep.Depth);
            Assert.AreEqual<int>(3, RequestHelper.r3Deep.Depth);
            Assert.AreEqual<int>(4, RequestHelper.r4Deep.Depth);
        }

        [TestMethod]
        /// <summary>Executes the TestUrlArgsEquals test.</summary>
        public void TestUrlArgsEquals() {
            UrlCompletedEventArgs a1 = CreateArgs(23, true, null, RequestHelper.rGoogle, null);
            UrlCompletedEventArgs a2 = CreateArgs(24, false, null, new Request("http://www.google.com", RequestHelper.rYahoo), null);
            UrlCompletedEventArgs b1 = CreateArgs(23, true, null, RequestHelper.rYahoo, null);
            Assert.AreEqual<UrlCompletedEventArgs>(a1, a2);
            Assert.AreNotEqual<UrlCompletedEventArgs>(a1, b1);
        }



        private bool CheckRequest(Request request, Uri uri, int depth, Request parent) {
            if (request.Uri != uri)
                return false;
            if (request.Depth != depth)
                return false;
            return (request.Parent == null && parent == null) || request.Parent.Equals(parent);
        }

        public UrlCompletedEventArgs CreateArgs(int id, bool isTextResponse, System.IO.Stream stream, Eas.WebCrawler.Interfaces.Request request, Eas.WebCrawler.Interfaces.TemporaryStorage store ) {
            return new UrlCompletedEventArgs(new TestProcessingState(id, request, isTextResponse, stream), store);
        }

    }
}
